<?php

namespace Simanx\Spes\Attribute\Route\Permission;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Arr;
use Simanx\Spes\Module\ModuleManager;

class PermissionManager implements Arrayable
{
    /**
     * 所有的权限
     * @var array|(Permission|PermissionGroup)[]
     */
    private array $permissions = [];

    private ModuleManager $moduleManager;

    private string $cachePath;

    private bool $hasLoaded = false;

    public function __construct()
    {
        $this->moduleManager = app(ModuleManager::class);
        $this->cachePath = app()->bootstrapPath('cache/permission.php');
    }

    /**
     * 增加权限
     * @param Permission|PermissionGroup $permission
     */
    public function add(Permission|PermissionGroup $permission)
    {
        $this->permissions[$permission->permission()] = $permission;
    }

    public function permissions()
    {
        if ($this->hasLoaded) {
            return $this->permissions;
        }

        if ($permissions = config('permissions')) {
            return $this->permissions = $permissions;
        }

        if ($this->permissionAreCache()) {
            return $this->permissions = require $this->getCachePath();
        }

        $controllerDirs = $this->moduleManager->modulesDir('controller');
        app(PermissionLoader::class, [
            'app'    => app(),
            'config' => [
                'path' => $controllerDirs
            ]
        ])->load();
        $this->hasLoaded = true;
        return $this->permissions;
    }

    /**
     * 覆盖设置所有权限
     * @param array $permissions
     * @return void
     */
    public function setPermissions(array $permissions = [])
    {
        $this->permissions = $permissions;
        $this->hasLoaded = true;
    }

    /**
     * 树状权限组
     * @return array
     */
    public function tree()
    {
        return Arr::undot($this->toArray());
    }

    public function toArray()
    {
        $permissions = [];
        foreach ($this->permissions() as $key => $permission) {
            $permissions[$key] = is_array($permission) ? $permission : $permission->toArray();
        }

        return $permissions;
    }

    public function setCachePath(string $path)
    {
        $this->cachePath = $path;
    }

    public function getCachePath(): string
    {
        return $this->cachePath;
    }

    public function permissionAreCache()
    {
        return app('files')->exists($this->getCachePath());
    }
}
